استكشف ميزات TypeScript المتقدمة مثل أنواع الحروف للقالب والأنواع الشرطية لكتابة تعليمات برمجية أكثر تعبيرًا وقابلية للصيانة.
TypeScript: إتقان الأنواع الحرفية للقالب والأنواع الشرطية
تكمن قوة TypeScript في نظام الأنواع الخاص بها. في حين أن الأنواع الأساسية مثل string وnumber وboolean كافية للعديد من السيناريوهات، فإن الميزات المتقدمة مثل أنواع الحروف للقالب والأنواع الشرطية تفتح مستوى جديدًا من التعبير وسلامة الأنواع. يقدم هذا الدليل نظرة عامة شاملة على هذه الأنواع المتقدمة، ويستكشف إمكانياتها ويوضح التطبيقات العملية.
فهم أنواع الحروف للقالب
تبني أنواع الحروف للقالب على الحروف القالبية في JavaScript، مما يسمح لك بتحديد الأنواع بناءً على استيفاء السلسلة النصية. يتيح ذلك إنشاء أنواع تمثل أنماط سلاسل نصية محددة، مما يجعل التعليمات البرمجية الخاصة بك أكثر قوة وقابلية للتنبؤ.
الصيغة الأساسية والاستخدام
تستخدم أنواع الحروف للقالب علامات الاقتباس الخلفية (`) لتغليف تعريف النوع، على غرار الحروف القالبية في JavaScript. داخل علامات الاقتباس الخلفية، يمكنك استيفاء أنواع أخرى باستخدام صيغة ${}. هذا هو المكان الذي يحدث فيه السحر - فأنت تقوم فعليًا بإنشاء نوع عبارة عن سلسلة نصية، يتم إنشاؤها في وقت الترجمة بناءً على الأنواع الموجودة داخل الاستيفاء.
type HTTPMethod = "GET" | "POST" | "PUT" | "DELETE";
type APIEndpoint = `/api/${string}`;
// مثال للاستخدام
const getEndpoint: APIEndpoint = "/api/users"; // صالح
const postEndpoint: APIEndpoint = "/api/products/123"; // صالح
const invalidEndpoint: APIEndpoint = "/admin/settings"; // لن يظهر TypeScript خطأ هنا لأن `string` يمكن أن يكون أي شيء
في هذا المثال، APIEndpoint هو نوع يمثل أي سلسلة نصية تبدأ بـ /api/. في حين أن هذا المثال الأساسي مفيد، فإن القوة الحقيقية لأنواع الحروف للقالب تظهر عند دمجها مع قيود أنواع أكثر تحديدًا.
الجمع مع أنواع الاتحاد
تتألق أنواع الحروف للقالب حقًا عند استخدامها مع أنواع الاتحاد. هذا يسمح لك بإنشاء أنواع تمثل مجموعة محددة من تركيبات السلاسل النصية.
type HTTPMethod = "GET" | "POST" | "PUT" | "DELETE";
type APIPath = "users" | "products" | "orders";
type APIEndpoint = `/${APIPath}/${HTTPMethod}`;
// نقاط نهاية API الصالحة
const getUsers: APIEndpoint = "/users/GET";
const postProducts: APIEndpoint = "/products/POST";
// نقاط نهاية API غير الصالحة (ستؤدي إلى أخطاء TypeScript)
// const invalidEndpoint: APIEndpoint = "/users/PATCH"; // خطأ: "/users/PATCH" غير قابل للتخصيص للنوع "/users/GET" | "/users/POST" | "/users/PUT" | "/users/DELETE" | "/products/GET" | "/products/POST" | ... 3 المزيد ... | "/orders/DELETE".
الآن، APIEndpoint هو نوع أكثر تقييدًا يسمح فقط بتركيبات محددة لمسارات API وطرق HTTP. سيقوم TypeScript بتمييز أي محاولات لاستخدام تركيبات غير صالحة، مما يعزز سلامة الأنواع.
معالجة السلاسل النصية بأنواع الحروف للقالب
يوفر TypeScript أنواع معالجة السلاسل النصية الجوهرية التي تعمل بسلاسة مع أنواع الحروف للقالب. تسمح لك هذه الأنواع بتحويل السلاسل النصية في وقت الترجمة.
- Uppercase: يحول سلسلة نصية إلى أحرف كبيرة.
- Lowercase: يحول سلسلة نصية إلى أحرف صغيرة.
- Capitalize: يحول الحرف الأول من سلسلة نصية إلى حرف كبير.
- Uncapitalize: يحول الحرف الأول من سلسلة نصية إلى حرف صغير.
type Greeting = "hello world";
type UppercaseGreeting = Uppercase; // "HELLO WORLD"
type LowercaseGreeting = Lowercase; // "hello world"
type CapitalizedGreeting = Capitalize; // "Hello world"
type UncapitalizedGreeting = Uncapitalize; // "hello world"
تعد أنواع معالجة السلاسل النصية هذه مفيدة بشكل خاص لتوليد الأنواع تلقائيًا بناءً على اصطلاحات التسمية. على سبيل المثال، يمكنك استخلاص أنواع الإجراءات من أسماء الأحداث أو العكس.
التطبيقات العملية لأنواع الحروف للقالب
- تعريف نقاط نهاية API: كما هو موضح أعلاه، تحديد نقاط نهاية API مع قيود أنواع دقيقة.
- معالجة الأحداث: إنشاء أنواع لأسماء الأحداث مع بادئات ولواحق محددة.
- إنشاء فئات CSS: إنشاء أسماء فئات CSS بناءً على أسماء المكونات وحالاتها.
- بناء استعلامات قاعدة البيانات: ضمان سلامة الأنواع عند بناء استعلامات قاعدة البيانات.
مثال دولي: تنسيق العملات
تخيل بناء تطبيق مالي يدعم عملات متعددة. يمكنك استخدام أنواع الحروف للقالب لفرض تنسيق العملات الصحيح.
type CurrencyCode = "USD" | "EUR" | "GBP" | "JPY";
type CurrencyFormat = `${number} ${T}`;
const priceUSD: CurrencyFormat<"USD"> = "100 USD"; // صالح
const priceEUR: CurrencyFormat<"EUR"> = "50 EUR"; // صالح
// const priceInvalid: CurrencyFormat<"USD"> = "100 EUR"; // خطأ: النوع 'string' غير قابل للتخصيص للنوع '`${number} USD`'.
function formatCurrency(amount: number, currency: T): CurrencyFormat {
return `${amount} ${currency}`;
}
const formattedUSD = formatCurrency(250, "USD"); // النوع: "250 USD"
const formattedEUR = formatCurrency(100, "EUR"); // النوع: "100 EUR"
يضمن هذا المثال أن قيم العملات يتم تنسيقها دائمًا برمز العملة الصحيح، مما يمنع الأخطاء المحتملة.
التعمق في الأنواع الشرطية
تقدم الأنواع الشرطية منطق التفرع في نظام أنواع TypeScript، مما يسمح لك بتعريف أنواع تعتمد على أنواع أخرى. هذه الميزة قوية بشكل لا يصدق لإنشاء تعريفات أنواع مرنة وقابلة لإعادة الاستخدام بدرجة عالية.
الصيغة الأساسية والاستخدام
تستخدم الأنواع الشرطية الكلمة المفتاحية infer وعامل التشغيل الثلاثي (condition ? trueType : falseType) لتعريف شروط النوع.
type IsString = T extends string ? true : false;
type StringCheck = IsString; // نوع StringCheck = true
type NumberCheck = IsString; // نوع NumberCheck = false
في هذا المثال، IsString هو نوع شرطي يتحقق مما إذا كان T قابلاً للتخصيص للسلسلة النصية string. إذا كان الأمر كذلك، يحل النوع إلى true؛ وإلا، فإنه يحل إلى false.
الكلمة المفتاحية infer
تسمح لك الكلمة المفتاحية infer باستخلاص نوع من نوع. هذا مفيد بشكل خاص عند العمل مع أنواع معقدة مثل أنواع الدوال أو أنواع المصفوفات.
type ReturnType any> = T extends (...args: any) => infer R ? R : any;
function add(a: number, b: number): number {
return a + b;
}
type AddReturnType = ReturnType; // نوع AddReturnType = number
في هذا المثال، يستخلص ReturnType نوع الإرجاع لنوع الدالة T. الجزء infer R من النوع الشرطي يستدل على نوع الإرجاع ويقوم بتعيينه إلى متغير النوع R. إذا لم يكن T نوع دالة، يحل النوع إلى any.
الأنواع الشرطية التوزيعية
تصبح الأنواع الشرطية توزيعية عندما يكون النوع الذي تم فحصه معلمة نوع عارية. هذا يعني أن النوع الشرطي يتم تطبيقه على كل عضو في نوع الاتحاد بشكل منفصل.
type ToArray = T extends any ? T[] : never;
type NumberOrStringArray = ToArray; // نوع NumberOrStringArray = string[] | number[]
في هذا المثال، يقوم ToArray بتحويل نوع T إلى نوع مصفوفة. نظرًا لأن T هي معلمة نوع عارية (غير مغلفة في نوع آخر)، يتم تطبيق النوع الشرطي على number وstring بشكل منفصل، مما ينتج عنه اتحاد من number[] وstring[].
التطبيقات العملية للأنواع الشرطية
- استخلاص أنواع الإرجاع: كما هو موضح أعلاه، استخلاص نوع الإرجاع لدالة.
- تصفية الأنواع من اتحاد: إنشاء نوع يحتوي فقط على أنواع محددة من اتحاد.
- تعريف أنواع الدوال المتعددة التحميل: إنشاء أنواع دوال مختلفة بناءً على أنواع الإدخال.
- إنشاء حراس الأنواع: تعريف دوال تضييق نوع المتغير.
مثال دولي: معالجة تنسيقات التواريخ المختلفة
تستخدم مناطق مختلفة من العالم تنسيقات تواريخ مختلفة. يمكنك استخدام الأنواع الشرطية لمعالجة هذه الاختلافات.
type DateFormat = "YYYY-MM-DD" | "MM/DD/YYYY" | "DD.MM.YYYY";
type ParseDate = T extends "YYYY-MM-DD"
? { year: number; month: number; day: number; format: "YYYY-MM-DD" }
: T extends "MM/DD/YYYY"
? { month: number; day: number; year: number; format: "MM/DD/YYYY" }
: T extends "DD.MM.YYYY"
? { day: number; month: number; year: number; format: "DD.MM.YYYY" }
: never;
function parseDate(dateString: string, format: T): ParseDate {
// (سيقوم التنفيذ بمعالجة تنسيقات التواريخ المختلفة)
if (format === "YYYY-MM-DD") {
const [year, month, day] = dateString.split("-").map(Number);
return { year, month, day, format } as ParseDate;
} else if (format === "MM/DD/YYYY") {
const [month, day, year] = dateString.split("/").map(Number);
return { month, day, year, format } as ParseDate;
} else if (format === "DD.MM.YYYY") {
const [day, month, year] = dateString.split(".").map(Number);
return { day, month, year, format } as ParseDate;
} else {
throw new Error("تنسيق تاريخ غير صالح");
}
}
const parsedDateISO = parseDate("2023-10-27", "YYYY-MM-DD"); // النوع: { year: number; month: number; day: number; format: "YYYY-MM-DD"; }
const parsedDateUS = parseDate("10/27/2023", "MM/DD/YYYY"); // النوع: { month: number; day: number; year: number; format: "MM/DD/YYYY"; }
const parsedDateEU = parseDate("27.10.2023", "DD.MM.YYYY"); // النوع: { day: number; month: number; year: number; format: "DD.MM.YYYY"; }
console.log(parsedDateISO.year); // الوصول إلى السنة مع العلم أنها ستكون موجودة
يستخدم هذا المثال الأنواع الشرطية لتعريف دوال تحليل التواريخ المختلفة بناءً على تنسيق تاريخ التاريخ المحدد. يضمن النوع ParseDate أن الكائن المُرجع يحتوي على الخصائص الصحيحة بناءً على التنسيق.
الجمع بين أنواع الحروف للقالب والأنواع الشرطية
تأتي القوة الحقيقية عندما تجمع بين أنواع الحروف للقالب والأنواع الشرطية. هذا يسمح بتعاملات أنواع قوية بشكل لا يصدق.
type EventName = `on${Capitalize}`;
type ExtractEventPayload = T extends EventName
? { type: T; payload: any } // مبسط للتوضيح
: never;
type ClickEvent = EventName<"click">; // "onClick"
type MouseOverEvent = EventName<"mouseOver">; // "onMouseOver"
// مثال لدالة تأخذ نوعًا
function processEvent(event: T): ExtractEventPayload {
// في التنفيذ الحقيقي، سنقوم فعليًا بإرسال الحدث.
console.log(`Processing event ${event}`);
// في التنفيذ الحقيقي، ستستند الحمولة إلى نوع الحدث.
return { type: event, payload: {} } as ExtractEventPayload;
}
// لاحظ أن أنواع الإرجاع محددة للغاية:
const clickEvent = processEvent("onClick"); // { type: "onClick"; payload: any; }
const mouseOverEvent = processEvent("onMouseOver"); // { type: "onMouseOver"; payload: any; }
// إذا استخدمت سلاسل نصية أخرى، تحصل على never:
// const someOtherEvent = processEvent("someOtherEvent"); // النوع هو `never`
أفضل الممارسات والاعتبارات
- اجعلها بسيطة: على الرغم من قوتها، يمكن أن تصبح هذه الأنواع المتقدمة معقدة بسرعة. اسعَ لتحقيق الوضوح وقابلية الصيانة.
- اختبر بشكل شامل: تأكد من أن تعريفات الأنواع الخاصة بك تتصرف كما هو متوقع عن طريق كتابة اختبارات وحدات شاملة.
- وثق التعليمات البرمجية الخاصة بك: وثق بوضوح الغرض والسلوك الخاص بالأنواع المتقدمة لتحسين قابلية قراءة التعليمات البرمجية.
- ضع في اعتبارك الأداء: يمكن أن يؤثر الاستخدام المفرط للأنواع المتقدمة على وقت الترجمة. قم بقياس التعليمات البرمجية الخاصة بك وتحسينها عند الضرورة.
الخلاصة
تعد أنواع الحروف للقالب والأنواع الشرطية أدوات قوية في ترسانة TypeScript. من خلال إتقان هذه الأنواع المتقدمة، يمكنك كتابة تعليمات برمجية أكثر تعبيرًا وقابلية للصيانة وآمنة من حيث النوع. تتيح لك هذه الميزات التقاط العلاقات المعقدة بين الأنواع، وفرض قيود أكثر صرامة، وإنشاء تعريفات أنواع قابلة لإعادة الاستخدام بدرجة عالية. احتضن هذه التقنيات لرفع مستوى مهارات TypeScript الخاصة بك وبناء تطبيقات قوية وقابلة للتطوير لجمهور عالمي.